﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Threading;
using System.Runtime.InteropServices;

namespace RSCore.Helper.WPF
{
    // This code is inspired from :
    // http://blogs.msdn.com/pantal/archive/2007/07/31/managed-directx-interop-with-wpf-part-2.aspx
    sealed public class AirspaceOverlay : Decorator
    {

        #region Variables

        private Window transparentInputWindow;
        private Window _parent;
        double windowTopMargin;
        double windowLeftMargin;

        private Visibility _overlayChildVisible = Visibility.Hidden;

        private bool _fullWindow = false;

        #endregion

        #region Constructor

        public AirspaceOverlay()
        {
            transparentInputWindow = new Window();

            // Make the window itself transparent, with no style.
            transparentInputWindow.Background = Brushes.Transparent;
            transparentInputWindow.AllowsTransparency = true;
            transparentInputWindow.WindowStyle = WindowStyle.None;
            transparentInputWindow.ShowInTaskbar = false;
            transparentInputWindow.Focusable = false;

            // HACK: This window and it's child controls should never have focus, as window styling of an invisible window 
            // will confuse user.
            transparentInputWindow.PreviewMouseDown += new MouseButtonEventHandler(transparentInputWindow_PreviewMouseDown);
        }

        #endregion

        #region Close

        public void Close()
        {
            Dispatcher.Invoke(
                DispatcherPriority.Send,
                new Action(delegate()
                {
                    try
                    {
                        transparentInputWindow.Close();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                })
                );
        }

        #endregion

        #region Properties

        public Visibility OverlayChildVisibility
        {
            get
            {
                return _overlayChildVisible;
            }
            set
            {
                if (_overlayChildVisible == value)
                    return;
                _overlayChildVisible = value;
                OnChangeOverlayVisibility();
            }
        }

        public object OverlayChild
        {
            get
            {
                if (transparentInputWindow != null)
                    return transparentInputWindow.Content;

                return null;
            }
            set
            {
                if (transparentInputWindow != null)
                    transparentInputWindow.Content = value;
            }
        }

        #endregion

        #region OnRenderSizeChanged

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            UpdateWindow();
        }

        #endregion

        #region OnRender

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            if (_overlayChildVisible == Visibility.Visible &&
                transparentInputWindow.Visibility != Visibility.Visible)
            {
                UpdateWindow();
                transparentInputWindow.Show();
                _parent = GetParentWindow(this);
                transparentInputWindow.Owner = _parent;
                _parent.LocationChanged += new EventHandler(parent_LocationChanged);
            }
        }

        #endregion

        #region transparentInputWindow_PreviewMouseDown

        void transparentInputWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            _parent.Focus();
        }

        #endregion

        #region parent_LocationChanged

        private void parent_LocationChanged(object sender, EventArgs e)
        {
            UpdateWindow();
        }

        #endregion

        #region GetParentWindow

        private Window GetParentWindow(DependencyObject o)
        {
            DependencyObject parent = VisualTreeHelper.GetParent(o);
            if (parent == null)
            {
                FrameworkElement fe = o as FrameworkElement;
                if (fe != null)
                {
                    if (fe is Window)
                        return fe as Window;
                    else if (fe.Parent != null)
                        return GetParentWindow(fe.Parent);
                }
                throw new ApplicationException("A window parent could not be found for " + o.ToString());
            }


            return GetParentWindow(parent);
        }

        #endregion

        #region UpdateWindow

        private void UpdateWindow()
        {
            Window parentWindow = GetParentWindow(this);
            //Rect r = LayoutInformation.GetLayoutSlot((FrameworkElement)Parent);

            FrameworkElement parentElement = (FrameworkElement)Parent;
            if (parentElement.ActualWidth == 0 || parentElement.ActualHeight == 0)
                return;
            GeneralTransform transform = parentElement.TransformToAncestor(parentWindow);
            Point lt = transform.Transform(new Point(0, 0));

            transparentInputWindow.Left = parentWindow.Left + lt.X;
            transparentInputWindow.Top = parentWindow.Top + lt.Y;
            transparentInputWindow.Width = parentElement.ActualWidth;
            transparentInputWindow.Height = parentElement.ActualHeight;
        }

        #endregion

        #region OnChangeOverlayVisibility

        private void OnChangeOverlayVisibility()
        {
            if (_overlayChildVisible == Visibility.Visible &&
                transparentInputWindow.Visibility != Visibility.Visible)
            {
                UpdateWindow();
                transparentInputWindow.Show();
                _parent = GetParentWindow(this);
                transparentInputWindow.Owner = _parent;
                _parent.LocationChanged += new EventHandler(parent_LocationChanged);
            }
            else
                if (_overlayChildVisible == Visibility.Hidden &&
                transparentInputWindow.Visibility == Visibility.Visible)
                {
                    UpdateWindow();
                    transparentInputWindow.Hide();
                    _parent = GetParentWindow(this);
                    _parent.LocationChanged -= new EventHandler(parent_LocationChanged);
                }
        }

        #endregion

    }

}
